//
// Created by ta&to on 2022/9/26.
//

#ifndef HTTPSERVER_HTTP_SOCKET_H
#define HTTPSERVER_HTTP_SOCKET_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include "hash_util.h"
#define HTTPSERVER_OPEN 1 // 启用http 服务

#define NONE 0       /* No events registered. */
#define READABLE 1   /* Fire when descriptor is readable. */
#define WRITABLE 2   /* Fire when descriptor is writable. */

typedef struct event_container_s event_container_t;
typedef struct http_socket_event_s http_socket_event_loop_t;
typedef struct http_socket_event_handle_s http_socket_event_handle_t;

#if defined(__MINGW32__) || defined(__MINGW64__)
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <sys/unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#if defined(SOCKET_SERVER_POLL)
#include <poll.h>
#elif defined(SOCKET_SERVER_EPOLL)
#include <sys/epoll.h>
#endif
#endif
#ifdef HTTPSERVER_OPEN
#include "http_handler.h"
#endif

#define HTTP_SOCKET_CLOSE 0b01
#define HTTP_SOCKET_OPEN  0b10

#define HTTP_SOCKET_CLOSE_SERVER 0b01
#define HTTP_SOCKET_CLOSE_CLIENT 0b10

struct http_global_data_container{
    thread_pool_t *tpt;                           // 文件描述符全局锁 对于文件描述符的全局容器相关操作都要加锁
};
struct http_global_data_event_func_container{
    http_socket_event_handle_t *temp_func_handler;   // 局部数据模板
};
struct http_server_socket_fd_s {
    int fd;
};
struct http_client_socket_fd_s {
    int fd;
    int used;
    int can_use;
    pthread_mutex_t     use_lock;
};

struct http_server_http_connect_fd_s {
    int fd;
    int used;
    int can_use;
    pthread_mutex_t     use_lock;
};
struct event_container_s {
    log_t *logs;             // 日志
    int maxfd;               // 最大的链接描述符(数字)
    int max_link;            // 准备就绪队列的最大链接数
    int current_read_link;        // 当前连接数
    int current_write_link;        // 当前连接数
    struct timeval *tvp;
    struct event_fds_s *event_read_fds; // 链接的读文件描述符
    struct event_fds_s *event_write_fds; // 链接的写文件描述符
    int pipefd[2];
#ifdef SOCKET_SERVER_SELECT
    fd_set rfds;           // 用于存放需要监控的事件相关事件描述符的标识值 读
    fd_set wfds;           // 用于存放需要监控的事件相关事件描述符的标识值 写
#endif
#ifdef SOCKET_SERVER_POLL
    struct pollfd *poll_ev_fds;
#endif
#ifdef SOCKET_SERVER_EPOLL
    int epoll_fd; //epoll 自身的文件描述符
    struct event_use_fds_s* epoll_use_fds;
    struct epoll_event *epoll_ev_fds; // 准备就绪的文件描述符
#endif
    void *other;        // 用于扩展
    int status;
};
struct http_socket_event_s{
    struct event_container_s *ev_container;
    pthread_mutex_t     ev_c_lock;
    struct http_server_socket_fd_s socket_fd[MAX_CLINE];                     //监听套接字
    struct http_client_socket_fd_s client_fd[MAX_CLINE];                     // 前端与tserver建立的连接池
    struct http_server_http_connect_fd_s http_conn_fd[MAX_CLINE];            // tserver与后端接口建立的连接池
    char workpath[PATH_MAX];          // 项目路径
    log_t *logs;             // 日志
#ifdef HTTPSERVER_OPEN
    struct http_global_data_event_func_container *hgdefc;
    struct http_global_data_container *hgdc; // 用于存放http全局资源
#endif
};

static inline int indexserverOf(struct http_server_socket_fd_s *data, int size, int fd){
    void *data_ = NULL;
    for(int i = 0;i < size;i++) {
        data_ = data + i;
        if(((struct http_server_socket_fd_s*)data_)->fd == fd)
            return i;
    }
    return -1;
}

static inline int indexclientOf(struct http_client_socket_fd_s *data, int size, int fd){
    void *data_ = NULL;
    for(int i = 0;i < size;i++) {
        data_ = data + i;
        if(((struct http_client_socket_fd_s*)data_)->fd == fd)
            return i;
    }
    return -1;
}
static inline int updateclientArr(struct http_client_socket_fd_s *data, int size, int src_fd, struct http_client_socket_fd_s client_des_fd) {
    void *data_ = NULL;
    if(src_fd == 0) return -1;
    int index = indexclientOf(data, size, src_fd);
    if(index > -1) {
        data_ = data + index;
        (*(struct http_client_socket_fd_s*) data_) = client_des_fd;
        return 0;
    }
    return -1;
}
static inline int delclientArr(struct http_client_socket_fd_s *data, int size, int fd){
    void *data_ = NULL;
    if(fd == 0) return -1;
    int index = indexclientOf(data, size, fd);
    if(index > -1){
        data_ = data + index;
        ((struct http_client_socket_fd_s*)data_)->fd = 0;
        return fd;
    }
    return -1;
}
static inline int pushclientArr(struct http_client_socket_fd_s *data, int size, struct http_client_socket_fd_s client_fd) {
    void *data_ = NULL;
    if(indexclientOf(data, size, client_fd.fd) == -1){
        for(int i = 0;i < size;i++){
            data_ = data + i;
            if(((struct http_client_socket_fd_s*) data_)->fd == 0) {
                (*(struct http_client_socket_fd_s*) data_) = client_fd;
                return 0;
            }
        }
    }
    return -1;
}
typedef struct http_socket_event_s http_socket_event_t;
int CreateHttpClient(log_t *logt, const struct in_addr sin_addr, int port);
int CreateHttpSocket(log_t *logt, const in_addr_t listen_addr, int listen_port, int link_num);
int Accept(log_t *logt, int socket_fd, struct sockaddr *saddr, socklen_t *slen);
int putData(log_t *logt, const int socket_fd, char* buf, int len);
int getData(log_t *logt, const int socket_fd, char* buf, int len);
int vgetData(log_t *logt, const int client_fd, char* buf, int len);
int noSgPutData(log_t *logt,const int client_fd, char* buf, int len);
int Write(log_t *logt,const int client_fd, char* buf, int len);
int Recv(log_t *logt,const int client_fd, char* buf, int len);
int Read(log_t *logt,const int fd, char* buf, int len);
int connAccept(log_t *logt, http_socket_event_handle_t * handler, int fd);
int socketNonBlock(struct log_s *logt, int fd);
int socketBlock(struct log_s *logt, int fd);
void CloseAll(log_t *logt, int socket_fd, int client_fd);
#endif //HTTPSERVER_HTTP_SOCKET_H
